/*
 *
 *  Copyright (C) 2009 GSyC/LibreSoft
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see http://www.gnu.org/licenses/. 
 *
 *  Author : Roberto Calvo Palomino <rocapal@gsyc.es>
 *
 */

package com.LibreGeoSocial.App.Routes;

import java.util.ArrayList;
import java.util.List;
import java.util.Timer;

import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.PowerManager;
import android.preference.PreferenceManager;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.TextView;

import com.LibreGeoSocial.Api.LibreGeoSocial;
import com.LibreGeoSocial.Api.User;
import com.LibreGeoSocial.App.R;
import com.LibreGeoSocial.App.Overlay.PositionOverlay;
import com.LibreGeoSocial.App.Overlay.TraceOverlay;
import com.LibreGeoSocial.App.Utils.MapUtils;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;


public class RouteMap extends MapActivity implements Runnable {

	// Location provider, by default GPS
	static String LocationProvider = null;
	
	// Location Unit (seconds:1 or minutes:60), by default: seconds.
	static Integer LocationUnit = null;
	
	// Location Periodic in seconds, by default 2 minutes.
	static Integer LocationPeriodic = null; 
	
	// Set if the location is manual
	static Boolean ActiveManualLocation = null;
	
	// Minimum distance of gps refresh
	static Integer MinimumDistance = null;
	
	// Set if the storage is in sdcard
	static Boolean ActiveStorageSdCard = null;
	
	// Route Nodes
	private ArrayList<Location> positionNodes = new ArrayList<Location>();
	
	// Current location and current trace file
	static public String currentTracefile = null;
	static private String RouteSaveFile = null;
	
	public Location currentLocation = null;

	static boolean m_activeGPS = false;
	
	// Maps
	private GeoPoint map_center = null;
	private MapView mapView;
	
	private MapController mapController = null;
	private User user;
	

	
	// Menus
	private static final int MENU_SAVE_TRACE = Menu.FIRST + 1;
	private static final int MENU_READ_TRACES = Menu.FIRST + 2;
	private static final int MENU_SETTINGS = Menu.FIRST + 3;
	
	private static MenuItem itemActive = null;
	
	// Dialogs
	private static final int DIALOG_RECORD_TRACE = 1;
	//private ProgressDialog pd;
	
	// Capture route
	private static boolean recordTrace = false;
	private RouteManager trManager = null;

	
	// Power Manager
	protected PowerManager.WakeLock mWakeLock; 
		
	private Timer mTimer = null;
	
	public void onCreate(Bundle icicle) { 
		
		   super.onCreate(icicle);
		   
		   final PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); 
		   this.mWakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "label_screen"); 
		   this.mWakeLock.acquire(); 
		   
		   user = LibreGeoSocial.getInstance().getInfoUser(true, null);
		   currentLocation = LocationService.getCurrentLocation();
		   
		   FrameLayout frame = new FrameLayout(this);
		   
		   mapView = new MapView(this, getString(R.string.map_key));
		   mapController = mapView.getController();
		   
	       frame.addView(mapView, 
	                new FrameLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));

	       mapView.setOnTouchListener(touchListener);
		   setContentView(frame);	
		   
	       /* Settings map */
	       mapView.setClickable(true);
	       mapView.setEnabled(true);
	       mapView.setSatellite(false);

		   addZoomControls(frame);		   
		   setPositionInMap(17);		   
		   map_center = mapView.getMapCenter();
		   
		   
		   loadConfig();
		   
	}

	private void loadConfig ()
	{
		
		SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
		
		Editor editor = sharedPreferences.edit();

		// PROVIDER 
		String location = sharedPreferences.getString(RoutePreferences.KEY_LOCATION_PROVIDERS, null);
		
		if (location == null)
		{
			LocationProvider = LocationManager.GPS_PROVIDER;
			editor.putString(RoutePreferences.KEY_LOCATION_PROVIDERS, "gps");
		}
		else
		{
				
			if (location.equals("gps"))
				LocationProvider = LocationManager.GPS_PROVIDER;
			
			else if (location=="wifi")			
				LocationProvider = LocationManager.NETWORK_PROVIDER;
		}
			
		// Time unit
		String s_unit = sharedPreferences.getString(RoutePreferences.KEY_LOCATION_UNITS, null);
		
		if (s_unit == null)
		{
			LocationUnit = 60;
			editor.putString(RoutePreferences.KEY_LOCATION_UNITS, "60");
		}
		else
		{			
			Integer unit = Integer.valueOf(s_unit);
				
			LocationUnit = unit;
		}

		// Time periodic
		String s_periodic = sharedPreferences.getString(RoutePreferences.KEY_LOCATION_PERIODIC, null);
		
		if (s_periodic==null)
		{
			LocationPeriodic = 2;
			editor.putString(RoutePreferences.KEY_LOCATION_PERIODIC, "2");
			
		}
		else
		{
			Integer periodic = Integer.valueOf(s_periodic);
			RouteMap.LocationPeriodic = periodic;
		}
			
		// Manual Route
		Boolean manualLoc = sharedPreferences.getBoolean(RoutePreferences.KEY_LOCATION_MANUAL, false);
			
		ActiveManualLocation = manualLoc;
		editor.putBoolean(RoutePreferences.KEY_LOCATION_MANUAL, ActiveManualLocation);
		
		
		//Minimum Distance
		String s_minDistance = sharedPreferences.getString(RoutePreferences.KEY_LOCATION_DISTANCE, null);
		if (s_minDistance == null)
		{
			MinimumDistance = 10;
			editor.putString(RoutePreferences.KEY_LOCATION_DISTANCE, "20");
		
		}
		else
		{			
			Integer minDistance = Integer.valueOf(s_unit);				
			MinimumDistance = minDistance;
		}	
		
		// Storage in SDCARD
		Boolean storateSdCard = sharedPreferences.getBoolean(RoutePreferences.KEY_LOCATION_WRITERMODE, false);
			
		ActiveStorageSdCard = storateSdCard;
		editor.putBoolean(RoutePreferences.KEY_LOCATION_WRITERMODE, ActiveStorageSdCard); 
	
		editor.commit();
		
	}
	
	protected void onResume(){
		super.onResume();
		
		loadConfig();
		
		if (currentTracefile!=null)
		{
			RouteManager myTrManager;
 					
			myTrManager = new RouteManager(getBaseContext());
			
			myTrManager.setStorageSDCard(ActiveStorageSdCard);
			
			myTrManager.setTraceRealName(currentTracefile);
			positionNodes = myTrManager.readTraces();
			
			updatePositionInMap();
			setTracesInMap();
		}
		
		mapView.invalidate();
		
	}
	
    @Override
    public void onDestroy() {
         this.mWakeLock.release();
         
		// Stop timer
		if (mTimer!=null)
		{
			mTimer.cancel();
			mTimer = null;
		}
         
         currentTracefile = null;
         super.onDestroy();
    } 
    
    private OnTouchListener touchListener = new OnTouchListener(){

		public boolean onTouch(View v, MotionEvent event) {
			// TODO Auto-generated method stub
			
			switch(event.getAction()){
			
			case MotionEvent.ACTION_DOWN:
				map_center = mapView.getMapCenter();
				ActiveManualLocation = true;
				break;
				
			case MotionEvent.ACTION_MOVE:
				GeoPoint new_map_center = mapView.getMapCenter();
		    	
		    	double distance = Math.sqrt(Math.pow(new_map_center.getLatitudeE6()-map_center.getLatitudeE6(),2)+
		    			Math.pow(new_map_center.getLongitudeE6()-map_center.getLongitudeE6(),2));
		    	
		    	map_center = new_map_center;
		    	
		    	if(distance > 1)
		    		ActiveManualLocation = false;
		    	
				break;
			
			case MotionEvent.ACTION_UP:
				
				
				if (recordTrace && ActiveManualLocation)
				{
					//capture = false;
					
					Location loc = MapUtils.getLocFromXY(event.getX(), event.getY(), mapView, 0);
					
					currentLocation = loc;
					user.setLatitude(currentLocation.getLatitude());
					user.setLongitude(currentLocation.getLongitude());
					setPositionInMap(17);
					
					if (trManager!=null)
						trManager.saveTrace(currentLocation);
				}
				
				break;
				
			default:
					break;
			}
			
			return false;
		}
    };
    
    private void updatePositionInMap ()
    {
    
		if (positionNodes.size() > 0)
		{
			currentLocation = positionNodes.get(positionNodes.size()-1);
			
			user.setLatitude(currentLocation.getLatitude());
			user.setLongitude(currentLocation.getLongitude());
			
			LibreGeoSocial.getInstance().setUserPosition( currentLocation.getLatitude(), 
														  currentLocation.getLongitude(),
														  currentLocation.getAltitude());
			
			setPositionInMap(17);
		}
    	
    }
    
    private void setTracesInMap ()
    {    	        	

		final List<Overlay> overlays = mapView.getOverlays();
    	    	
		overlays.clear();
		
    	TraceOverlay myTraceOverlay = new TraceOverlay();
    	myTraceOverlay.setTrace (positionNodes);
    	   	
    	overlays.add(myTraceOverlay);
    	

    }
    
	private void setPositionInMap(int zoom){
		
		GeoPoint point = new GeoPoint(  (int) (currentLocation.getLatitude() * 1E6), 
				  (int) (currentLocation.getLongitude() * 1E6));
		
		mapController.animateTo(point);
		mapController.setZoom(zoom);

		PositionOverlay myposOverlay = new PositionOverlay();
        myposOverlay.setUser(user);
        
        mapView.getOverlays().clear();
        
	    final List<Overlay> overlays = mapView.getOverlays();	   
	    overlays.add( myposOverlay );
	    
	    map_center = mapView.getMapCenter();
	}
	
	/**
     * Get the zoom controls and add them to the bottom of the map
     */
    private void addZoomControls(FrameLayout frame) {
    	
        View zoomControls = mapView.getZoomControls();

        FrameLayout.LayoutParams p = 
            new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
                LayoutParams.WRAP_CONTENT, Gravity.BOTTOM + Gravity.CENTER_HORIZONTAL);
        frame.addView(zoomControls, p);
    }

	@Override
	protected boolean isRouteDisplayed() {
		// TODO Auto-generated method stub
		return false;
	}
	
	
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
    	
        super.onCreateOptionsMenu(menu);
        
        if (itemActive == null)
        {
	        menu.add(0, MENU_SAVE_TRACE, 0, "Record Route")
					.setIcon(R.drawable.record_48)
					.setAlphabeticShortcut('S');
        }
        else
        {
	        menu.add(0, MENU_SAVE_TRACE, 0, "Stop Route")
				.setIcon(R.drawable.stop_48)
				.setAlphabeticShortcut('S');
        }
        
        menu.add(0, MENU_READ_TRACES, 0, "Read Routes")
				.setIcon(R.drawable.play_48)
				.setAlphabeticShortcut('S');

        menu.add(0, MENU_SETTINGS, 0, "Settings")
				.setIcon(R.drawable.spanner_48)
				.setAlphabeticShortcut('S');
        
        return true;
    }
    
    @Override
    public boolean onOptionsItemSelected (MenuItem item) {
    
    	switch (item.getItemId()) {
    	
    	case MENU_SAVE_TRACE:
    		
    		if (recordTrace)
    		{
    			item.setTitle("Record Trace");
    			item.setIcon(R.drawable.record_48);
    			
    			itemActive = null;
    			trManager = null;
    			recordTrace = false;    			    			

    			LocationService.setRouteUpdateListener (null);
    		}
    		else
    		{
    			itemActive = item;
	    		showDialog(DIALOG_RECORD_TRACE);

    		}
    		break;
    		
    	case MENU_READ_TRACES:
    		
    		Intent i = new Intent(this, RouteList.class);
        	
    		i.putExtra("storage", ActiveStorageSdCard);
    		
        	startActivity(i);
        	
    		break;    	
    	
    	
    	case MENU_SETTINGS:

    		
    		Intent i2 = new Intent(this, RoutePreferences.class);        	
        	startActivity(i2);

    		break;
    	
    	}
    	
    	return super.onOptionsItemSelected(item);
    
    }
    
    private void initRoute() {
    	
		Thread thread = new Thread(this);
		thread.start();

    }
     
    
    @Override
    protected Dialog onCreateDialog(int id) {
        
    	switch (id) {
	    	case DIALOG_RECORD_TRACE:
	    		
	    		LayoutInflater factory = LayoutInflater.from(this);
	    		final View textEntryView = factory.inflate(R.layout.state, null);
	    		
	    		final EditText edit = (EditText) textEntryView.findViewById (R.id.txtstate);
	    		final TextView tview = (TextView) textEntryView.findViewById (R.id.state_view);
	    		
	    		edit.setText("");
	    		tview.setText("Type the name of Route:");
	    		
		        return new AlertDialog.Builder(this)	        
		        .setTitle("Record Route")
		        .setView(textEntryView)
		        .setPositiveButton("Record", new DialogInterface.OnClickListener() {
		            public void onClick(DialogInterface dialog, int whichButton) 
		            {
		            	
		            	RouteSaveFile = edit.getText().toString();
	    	    		itemActive.setTitle("Stop Route");
	    	    		itemActive.setIcon(R.drawable.stop_48);
	    	    		
	            		recordTrace = true;	        
	            		
	            		initRoute();

		            }
		        })
		        .setNegativeButton("cancel", new DialogInterface.OnClickListener() {
		            public void onClick(DialogInterface dialog, int whichButton) {
		            	
		            	itemActive = null; 

		            }
		        })
		        .create();
		    
    	}
    	
    	return null;
    }

	public void run() {

		startService(new Intent(this,LocationService.class));		
		
		LocationService.setProvider (LocationManager.GPS_PROVIDER);
		LocationService.setTraceName (RouteSaveFile);
		LocationService.setRouteUpdateListener ( new IRouteServiceListener () {
			
			public void updateRoutePoints ( final ArrayList<Location> points)
			{	
				positionNodes = points;
				
				updatePositionInMap();
				
				mapView.invalidate();				

			}
		});
		
	}

    

}
